#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.linear_model import LogisticRegression

def sigmoid(z):  
    a = 1.0 / (1 + np.exp(-z))
    return a

def lodistic(X,Y,alpha,numloop):
        
    """
        X : train data
        Y : labels of X
        alpha : learning efficiency,0-1.0
        numloop : numbers of loop so as to get the exact result
    """
    nx, m = X.shape
    #初始化
    w = np.zeros((nx,1))
    b = 0   
    for i in np.arange(numloop):
        Z = np.dot(w.T, X) + b
        A = sigmoid(Z)
        dz = A - Y
        dw = np.dot(X,dz.T)/m
        db = np.sum(dz)/m        
        #梯度下降
        w = w - alpha*dw
        b = b - alpha*db
    return (w,b)

class DataOperatio:
    def data_split(X,Y,image,testnum):
        
        """split data to train data and test data
        """
        choosetest = np.random.choice(np.arange(1797),size = testnum)
        choosetrain = np.delete(np.arange(1797),choosetest) 
        X_test = X[choosetest[:]]
        X_train = X[choosetrain[:]]
        Y_test = Y[choosetest[:]]
        Y_train = Y[choosetrain[:]]
        image_test = image[choosetest[:]]
        
        return (X_train,X_test,Y_train,Y_test,image_test)
    
    def plot_error(Error,image_test,Y_test,Y_pred,who):
        
        """plot the wrong classification
           Error: list of indexs of error
           image_test: test datasets of data.image
           Y_pred: prediction of logistic base on Y_test
        """
        fig = plt.figure(figsize=(6, 6))  # figure size in inches
        if who == 'my':
            plt.title("my error")
        else:
            plt.title("sklearn error")
        fig.subplots_adjust(left=0, right=1, bottom=0, top=1,
                            hspace=0.05, wspace=0.05)
        for i in range(len(Error)):
            ax = fig.add_subplot(8, 8, i + 1, xticks=[], yticks=[])
            ax.imshow(image_test[Error[i]], cmap=plt.cm.binary)
                
            # label the image with the target value
            ax.text(0, 7, str(Y_test[Error[i]])) #TRUE
            ax.text(0, 1, str(Y_pred[Error[i]]))  #Negative
    
    def class_i(A,num):
        """
        creat num_th classification
        """
        B = A.copy()
        B[B!=num] = -1
        B[B==num] = 1
        B[B==-1] = 0  
        return B
       
    def error_rate(Error):
        rate = len(Error)/1797*100
        return rate


# load datas
digits = load_digits()
X = digits.data
Y = digits.target
image = digits.images      
test_size = 0.250
num_test = int(1797*test_size)+1
num_train = 1797-num_test 
Y_total = np.ones((num_test,10))
myERROR = []
skERROR = []

#train and test data
X_train, X_test, Y_train, Y_test, image_test = DataOperatio.data_split(
                                                    X, Y, image, testnum=num_test)
#logisitic regr
for i in np.arange(10):
    Y_class = DataOperatio.class_i(Y_train,i)
    w, b= lodistic(X_train.T,Y_class,alpha=0.1,numloop=60)
    Y_total[:,i] = sigmoid(np.dot(w.T, X_test.T) + b)
    cls = LogisticRegression().fit(X_train,Y_train)
    Y_skpredict = cls.predict(X_test)
    
Pmax = np.argmax(Y_total,axis=1)
Y_predict = digits.target_names[Pmax[:]]



#Error classification
for i in np.arange(num_test):
    if Y_predict[i] != Y_test[i]:
        myERROR.append(i)
    if Y_skpredict[i] != Y_test[i]:
        skERROR.append(i)
        
num_myerror = len(myERROR)//64 + 1
num_skerror = len(skERROR)//64 + 1
for i in range(num_myerror):
    start = i*64
    end = (i+1)*64
    if end>len(myERROR):
        A = myERROR[start:].copy()
    else:
        A = myERROR[start:end].copy()
    DataOperatio.plot_error(A,image_test,Y_test,Y_predict,who='my')
    
for i in range(num_skerror):
    start = i*64
    end = (i+1)*64
    if end>len(skERROR):
        A = skERROR[start:].copy()
    else:
        A = skERROR[start:end].copy()
    DataOperatio.plot_error(A,image_test,Y_test,Y_skpredict,who='sk')

myrate = DataOperatio.error_rate(myERROR)
skrate = DataOperatio.error_rate(skERROR)
print("error rate of my logistic:{}%".format(myrate))
print("error rate of sk logistic:{}%".format(skrate))



 
        


        
        
        
        
        
        
        
        
        
        
        
        
        